This is an R Markdown Notebook. When you execute code within the notebook, the results appear beneath the code.

Try executing this chunk by clicking the Run button within the chunk or by placing your cursor inside it and pressing Ctrl+Shift+Enter.

library(spatstat)
library(sp)
library(rgeos)
library(maptools)
library(GISTools)
install.packages("tidyverse")
library(tmap)
library(sf)
library(geojsonio)
library(tmaptools)
library(tidyverse)
library(rgdal)
library(raster)
library(SciViews)
library(base)
library(broom)
library(spdep)
####Basemap
library(tmap)
BoroughMap <- geojson_read("https://raw.githubusercontent.com/ft-interactive/geo-data/master/uk/london/london-wards-2014.geojson", what = "sp")
BNG = "+init=epsg:27700"
BoroughMapBNG <- spTransform(BoroughMap,BNG)
WGS = "+init=epsg:4326"
tmap_mode("view")
tm_shape(BoroughMapBNG) +tm_polygons(col = NA, alpha = 0.5)

#aggregate city of london 
library(sf)
library(dplyr)
library(rgdal)
BoroughMapSF <- st_as_sf(BoroughMapBNG)
library(rgeos)
CityofLondon<- gUnionCascaded(BoroughMapBNG[c(630:654), ])
plot(CityofLondon)
CityofLondonSF <- st_as_sf(CityofLondon)
CityofLondonSF$gss_code_ward<-"E05000001"  ##add same columns in city of london, for aggregating with other borough
CityofLondonSF$gss_code_borough <- "E09000001"
CityofLondonSF$borough <-"City Of London"
CityofLondonSF$ward <- "City Of London"
BoroughMapSFnew <- BoroughMapSF[-c(630:654), ]
LondonWardSF <- rbind(BoroughMapSFnew,CityofLondonSF) ##Attention New not new
LondonWard <- as(LondonWardSF,"Spatial")
rownames(LondonWardSF) <- 1:nrow(LondonWardSF)
tmap_mode("view")
tm_shape(LondonWard) +tm_polygons(col = NA, alpha = 0.5)#+tm_text("ward",size=0.3, col="black") 
####population density (using https://data.london.gov.uk/dataset/land-area-and-population-density-ward-and-borough 2016)
library(tidyverse)
Density <- read_csv("E:/UCL/005-GI System&Science/GIS-Assessment 3/R assessment3/population_density_2016_final.csv",na = "n/a")
#normalization population_per_square_km
normalization<-function(x){
return((x-min(x))/(max(x)-min(x)))}
density.normalization <- normalization(Density$`population density`)
Density$Density.normalization <- density.normalization

#join the data to basemap P3P27
LondonWard.join.popdens <- LondonWardSF%>% left_join(Density,by=c("gss_code_ward"="New Code"))
tmap_mode("view")
qtm(LondonWard.join.popdens,fill="Density.normalization")
### Public transport accessibility level(PTAL)
PTAL <- read_csv("E:/UCL/005-GI System&Science/GIS-Assessment 3/R assessment3/Ward2014 Avpublic transport accessibility level2015.csv",na = "n/a")
#normalization PTAL
normalization<-function(x){
return((x-min(x))/(max(x)-min(x)))}
PTAL.normalization <- normalization(PTAL$AvPTAI2015)
PTAL$PTAL.normalization <- PTAL.normalization
#join the data to basemap P3P27
LondonWard.join.PTAL <- LondonWardSF%>% left_join(PTAL,by=c("gss_code_ward"="Ward Code"))
qtm(LondonWard.join.PTAL,fill="PTAL.normalization")
qtm(LondonWard.join.PTAL,fill="AvPTAI2015")

###Public open space accessibility level(POSAL)
POSAL <- read_csv("E:/UCL/005-GI System&Science/GIS-Assessment 3/R assessment3/access_public_open_space_ward.csv",na = "n/a")
POSAL$POSAL.normalization <- normalization(POSAL$`Open Space`)
LondonWard.join.POSAL <- LondonWardSF%>% left_join(POSAL,by=c("gss_code_ward"="WD13CD"))
#qtm(LondonWard.join.POSAL,fill="POSAL.normalization")
#combine two accessibility sub-index
Access.normalization<- merge(POSAL,PTAL, by.x="WD13CD",by.y="Ward Code",all=TRUE)
#remove useless column and rows
Access.normalization[,c(4:8,10:11)] <- NULL
#calculate the mean of two accessibility level
Access.normalization$access.mean <- rowMeans(Access.normalization[c('PTAL.normalization', 'POSAL.normalization')], na.rm=TRUE)

node

### Road intersections
node <- readOGR("E:/UCL/005-GI System&Science/GIS-Assessment 3/R assessment3/Road Networkoproad_essh_gb/new_road_node.shp",layer="new_road_node")
BNG = "+init=epsg:27700"
nodeBNG <- spTransform(node, BNG)
summary(node)
##qtm(nodeBNG)
nodeBNGSF <- st_as_sf(nodeBNG)
#select the node type"junction"
nodeBNGSF <- nodeBNGSF[which(nodeBNGSF$formOfNode=="junction"),]
nodeBNGSP <- as(nodeBNGSF, "Spatial")
head(node)
#select node point in borough
nodeBNGSP <- remove.duplicates(nodeBNGSP)
nodeBNGSP.final<- nodeBNGSP[LondonWard,]
# tmap view
#tmap_mode("view")
#tm_shape(LondonWard) +
#  tm_polygons(col = NA, alpha = 0.5) +
#tm_shape(nodeBNGSP.final) +
#  tm_dots(col = "blue")

# count number of point in each ward 
library(GISTools)
poly.counts(nodeBNGSP.final, LondonWard) -> nodecount
##setNames(nodecount, LondonWard@data$nodecount)
London.node <- LondonWardSF
London.node$nodecount <- nodecount   #add number of point to each ward (London.node$nodecount)
#combine the ward area(sq km)
London.node$Square_Kilometres <- LondonWard.join.popdens$`Square Kilometres`
#calculate point/area--point per square kilometre
London.node$PointPerSK <-London.node$nodecount/London.node$Square_Kilometres
qtm(London.node,fill="PointPerSK")
#join with LondonWardSF
London.nodeSF <- append_data(LondonWardSF,London.node, key.shp = "code", key.data = "gss_code_ward", ignore.duplicates = TRUE)

economic vitality

###economic vitality
#CLASS 1  house price
#HousePrice <- read_csv("E:/UCL/005-GI System&Science/GIS-Assessment 3/R assessment3/house_price_mean2016.csv",na = "n/a")
#HousePrice.normalization <- normalization(HousePrice$Value)
#HousePrice$HousePrice.normalization <- HousePrice.normalization
#CLASS 2 economic activity
EcoAct <- read_csv("E:/UCL/005-GI System&Science/GIS-Assessment 3/R assessment3/economic_activity_ward.csv",na = "n/a")
EcoAct.normalization <- normalization(EcoAct$`Economically active: Total`)
EcoAct$EcoAct.normalization <- EcoAct.normalization

land use mix

### Land use mix
#https://en.wikipedia.org/wiki/Planning_use_classes_in_England 
# six classes--
landcover <- readOGR("E:/UCL/005-GI System&Science/GIS-Assessment 3/R assessment3/greater-london-latest-free.shp/gis_osm_landuse_a_free_1.shp",layer="gis_osm_landuse_a_free_1")
landcoverBNG <- spTransform(landcover, BNG)
landcoverBNGSF <- st_as_sf(landcoverBNG)

AOIS <- readOGR("E:/UCL/005-GI System&Science/GIS-Assessment 3/R assessment3/greater-london-latest-free.shp/gis_osm_pois_a_free_1.shp",layer="gis_osm_pois_a_free_1")
AOISBNG <- spTransform(AOIS, BNG)
AOISBNGSF <- st_as_sf(AOISBNG)

#find missing data in each column in landcoverBNGSF
colSums(is.na(landcoverBNGSF))
#get the classes of landcover
summary(landcoverBNGSF)
#CLASS1 greenspace
greenspaceBNGSF <- landcoverBNGSF[ which( landcoverBNGSF$fclass =="park" |  landcoverBNGSF$fclass =="forest"|landcoverBNGSF$fclass =="nature_reserve"|landcoverBNGSF$fclass =="grass"),] 
greenspaceBNGSP <- as(greenspaceBNGSF,"Spatial")
#CLASS2 industrial and commercial
industrialBNGSF <- landcoverBNGSF[ which( landcoverBNGSF$fclass =="industrial"| landcoverBNGSF$fclass =="commercial"),]
industrialBNGSP <- as(industrialBNGSF,"Spatial")
#CLASS 3 residential
residentialBNGSF <- landcoverBNGSF[ which( landcoverBNGSF$fclass =="residential" ),]
residentialBNGSP <- as(residentialBNGSF,"Spatial")
#CLASS 4 recreation-leisure
recreationBNGSF1 <- landcoverBNGSF[ which( landcoverBNGSF$fclass =="recreation_ground"| landcoverBNGSF$fclass =="allotments"),]
recreationBNGSF2 <- AOISBNGSF[ which(AOISBNGSF$fclass =="attraction"|AOISBNGSF$fclass =="theatre"|AOISBNGSF$fclass =="arts_centre"),]
recreationBNGSF <- rbind(recreationBNGSF2,recreationBNGSF1)
recreationBNGSP <- as(recreationBNGSF,"Spatial")


#CLASS 5 retail
retailBNGSF1 <- landcoverBNGSF[ which( landcoverBNGSF$fclass =="retail" ),]
retailBNGSF2 <- AOISBNGSF[ which( AOISBNGSF$fclass =="retail" ),]
retialBNGSF <- rbind(retailBNGSF2,retailBNGSF1)
retailBNGSP <- as(retailBNGSF,"Spatial")

#CLASS 6--community services
communityBNGSF <- AOISBNGSF[ which(AOISBNGSF$fclass =="school"|AOISBNGSF$fclass =="hospital"|AOISBNGSF$fclass =="nursing_home"|AOISBNGSF$fclass =="university"  ),]
communityBNGSP <- as(communityBNGSF,"Spatial")

#CLASS 7--transport
transport <- readOGR("E:/UCL/005-GI System&Science/GIS-Assessment 3/R assessment3/greater-london-latest-free.shp/road_polygon_merge.shp",layer="road_polygon_merge")
transportBNG <- spTransform(transport, BNG)
transportBNG <- transportBNG[transportBNG@data$AREA >10000,] 
# Assign the land use area for each subset. Here we first use the most widespread residential as example 
library(raster)
r <- raster(ncols=400, nrows=400) #generate raster size(quantity)
extent(r) <- extent(residentialBNGSP)  #Important! Assign the extent of raster to cover the same extents of the polygon
residential.Raster <- rasterize(residentialBNGSP,r,background=NA) #convert polygon to raster
#tmap_mode("view")
#qtm(residential.Raster)+tm_shape(LondonWard) +tm_polygons(col = NA, alpha = 0.5)
#extract rasters from polygons#(extract() cannot use method=bilinear in raster-in-polygon)
residential.extract <- raster::extract(residential.Raster,LondonWard,df=TRUE, weights =FALSE, na.rm = TRUE)
#remove rows with NA
row.has.na <- apply(residential.extract, 1, function(x){any(is.na(x))})
residential.extract2 <-residential.extract[!row.has.na,]
#merge the pixel in same ward(aggregate the frequency of the same data in one)
library(plyr)
residential.extract.sum <- factor(residential.extract2$ID)  
residential.extract.sum <- table(residential.extract2$ID)
residential.extract.wardsum <- as.data.frame(residential.extract.sum)
#create new order number for LondonWardSF, for merge the residential.extract and LondonWardSF by order
LondonWard2SF <- LondonWardSF
LondonWard2SF$Var1 <- 1:630
LondonWard2SF[,'Var1']<-factor(LondonWard2SF[,'Var1'])
#merge two dataframe
residential.extract.final <- merge(residential.extract.wardsum, LondonWard2SF, by="Var1",all=TRUE)
#residential.extract.final [!duplicated(residential.extract.final ), ]
#replace NA values with 0
residential.extract.final[is.na(residential.extract.final)] <- 0
#rename the column
colnames(residential.extract.final)[2] <- "Freq.residential"
#raster cell size
#we have to convert raster to polygon because of raster(). This function only compute the pixel area in longitude/latitude coordiante system
residential.repolygon <- rasterToPolygons(residential.Raster, fun=NULL, n=4, na.rm=TRUE, digits=12, dissolve=TRUE)
#qtm(residential.repolygon)
residential.repolygonSF <- st_as_sf(residential.repolygon) 
residential.repolygonSF$area <- st_area(residential.repolygonSF)
#so the single pixel area is 28999.54 [m^2](0.029 km^2)

land use mix functions

##based on the details above, we create functions for land use analysis
function.raster <- function(landsp){
  extent(r) <- extent(landsp)
  landsp.Raster <- rasterize(landsp,r,background=NA)
  return(landsp.Raster)
}

function.extract<- function(landsp.Raster){
  landsp.extract <- raster::extract(landsp.Raster,LondonWard,df=TRUE, weights =FALSE, na.rm = TRUE)
  row.has.na <- apply(landsp.extract, 1, function(x){any(is.na(x))})
  landsp.extract2 <-landsp.extract[!row.has.na,]
  landsp.extract.sum <- factor(landsp.extract2$ID)  
  landsp.extract.sum <- table(landsp.extract2$ID)
  landsp.extract.wardsum <- as.data.frame(landsp.extract.sum)
  landsp.extract.final <- merge(landsp.extract.wardsum, LondonWard2SF, by="Var1",all=TRUE)
  landsp.extract.final[is.na(landsp.extract.final)] <- 0
  return(landsp.extract.final)
}
#green space raster
greenspace.Raster <- function.raster(greenspaceBNGSP)
greenspace.extract.final <- funtion.extract(greenspace.Raster)
colnames(greenspace.extract.final)[2] <- "Freq.greenspace"

#industrial and commercial
industrial.Raster <- function.raster(industrialBNGSP)
industrial.extract.final <- function.extract(industrial.Raster)
colnames(industrial.extract.final)[2] <- "Freq.industrial"
#recreation
recreation.Raster <- function.raster(recreationBNGSP)
recreation.extract.final <- function.extract(recreation.Raster)
colnames(recreation.extract.final)[2] <- "Freq.recreation"
#retail
retail.Raster <- function.raster(recreationBNGSP)
retail.extract.final <- function.extract(retail.Raster)
colnames(retail.extract.final)[2] <- "Freq.retail"
#community
community.Raster <- function.raster(communityBNGSP)
community.extract.final <- function.extract(community.Raster)
colnames(community.extract.final)[2] <- "Freq.community"
#transport
transport.Raster <- function.raster(transportBNG)
transport.extract.final <- function.extract(transport.Raster)
colnames(transport.extract.final)[2] <- "Freq.transport"

tmap_mode("view")
tm_shape(LondonWard) +tm_polygons(col = NA, alpha = 0.2)+qtm(recreation.Raster)
#tm_shape(LondonWard) +tm_polygons(col = NA, alpha = 0.2)+qtm(residential.Raster)

#extract useful columns from multiple dataframe
landuse.dataframe <- residential.extract.final
landuse.dataframe <- merge(landuse.dataframe,greenspace.extract.final, by="Var1",all=TRUE)
landuse.dataframe <- merge(landuse.dataframe,industrial.extract.final, by="Var1",all=TRUE)
landuse.dataframe <- merge(landuse.dataframe,recreation.extract.final, by="Var1",all=TRUE)
landuse.dataframe <- merge(landuse.dataframe,retail.extract.final, by="Var1",all=TRUE)
landuse.dataframe <- merge(landuse.dataframe,community.extract.final, by="Var1",all=TRUE)
landuse.dataframe <- merge(landuse.dataframe,transport.extract.final, by="Var1",all=TRUE)
landuse.dataframe[,c(9:13,15:19,21:25,27:31,33:37,39:43)] <- NULL #remove useless column
colnames(landuse.dataframe)[2] <- "residential.freq" #rename column
head(landuse.dataframe)
index.dataframe[is.na(index.dataframe)] <- 0 
###compute land use mix index
index.dataframe$MixIndex <- (abs(rowSums(index.dataframe[,8:14])))/ln(7)
#MixIndex normalisation
index.dataframe$MixIndex.normalisation <- normalization(MixIndex )
Error in normalization(MixIndex) : object 'MixIndex' not found

qtm(residential.Raster)
library(tmap)
tmap_mode("view")
tm_shape(LondonWard) +
  tm_polygons(col = NA, alpha = 0.5) +
tm_shape(residentialBNGSP) +
  tm_polygons(col = "blue")

Test for the relationship

Linear regression model

###Since we have done the most important part of data manipulation, next we will explore the relationship between intersection and vitality
#histogram of two variables
qplot(PointPerSK, data = London.node, geom = "histogram")

#ggplot(London.node, aes(x="PointPerSK", y=PointPerSK))+geom_boxplot()#(this is another code for boxplot in ggplot2)
#qplot(y=London.node$PointPerSK, x= 0.1, geom = "boxplot")  
qplot(Index, data = index.dataframe, geom = "histogram")

#qplot(y= index.dataframe$Index, x= 0.1, geom = "boxplot")  
#the variables look normally distributed,but we should consider the outliers
plot(London.node$PointPerSK,index.dataframeSF$Index,col="blue")

#after scatter plot, we should remove "Lady Margaret" as its unusual road intersection density(maybe due to the residential road intersections are included)
node.index.frame <-merge(index.dataframe,London.node, by.x="gss_code_ward",by.y="gss_code_ward",all=TRUE) 
#remove outlier--Lady Margaret(E05000181)
#node.index.frame <- node.index.frame[node.index.frame$PointPerSK<300,]
#linear regression plot
qplot(PointPerSK,Index,data=node.index.frame,geom = "point") + stat_smooth(method="lm", se=FALSE, size=1)

#fit the linear model
model <- lm(PointPerSK ~ Index, data =node.index.frame)
#residual dataframe
library(broom)
model_res <- tidy(model)
summary(model)

Call:
lm(formula = PointPerSK ~ Index, data = node.index.frame)

Residuals:
    Min      1Q  Median      3Q     Max 
-80.543 -20.260  -5.167  13.257 198.842 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)  -12.822      6.281  -2.041   0.0416 *  
Index        246.958     14.180  17.416   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 32.48 on 628 degrees of freedom
Multiple R-squared:  0.3257,    Adjusted R-squared:  0.3246 
F-statistic: 303.3 on 1 and 628 DF,  p-value: < 2.2e-16
plot(model)

Fitting a Quadratic Model

node.index.frame$PointPerSK2 <- (node.index.frame$PointPerSK)^2
quadratic.model <-lm(Index ~ PointPerSK + (PointPerSK2),data =node.index.frame)
plot(quadratic.model )

summary(quadratic.model)

Call:
lm(formula = Index ~ PointPerSK + (PointPerSK2), data = node.index.frame)

Residuals:
      Min        1Q    Median        3Q       Max 
-0.186415 -0.045824  0.002214  0.043010  0.277679 

Coefficients:
              Estimate Std. Error t value Pr(>|t|)    
(Intercept)  1.861e-01  1.235e-02   15.07   <2e-16 ***
PointPerSK   3.927e-03  2.265e-04   17.34   <2e-16 ***
PointPerSK2 -1.175e-05  9.728e-07  -12.08   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.06766 on 627 degrees of freedom
Multiple R-squared:  0.4529,    Adjusted R-squared:  0.4512 
F-statistic: 259.6 on 2 and 627 DF,  p-value: < 2.2e-16
#node.index.frame$Index<- 1.861e-01+(3.927e-03)*(node.index.frame$PointPerSK)+(-1.175e-05)*(node.index.frame$pointPerSK2)
#plot(node.index.frame$PointPerSK,node.index.frame$Index,type='l',col='navy',main='Nonlinear relationship',lwd=3)
PointPerSKvalues <- seq(0,300, 0.01)
predictedcounts <- predict(quadratic.model,list(PointPerSK=PointPerSKvalues, PointPerSK2=PointPerSKvalues^2))
plot(node.index.frame$PointPerSK, node.index.frame$Index , pch=16, xlab = "PointPerSK", ylab = "Index", cex.lab = 0.8, col = "black")
lines(PointPerSKvalues, predictedcounts, col = "blue", lwd =2)

The coefficient (estimate) in the summary() table shows that(on average) for a 1 unit (day) increase in unauthorised absence from school, there is a reduction in the average GCSE point score of -29.874.

The p-values for the intercept and the coefficient are highly statistically significant (<0.001) so we can rely on the relationship that is being observed.

The adjusted R-squared statistic is 0.38, which tells us that 38% of the variation in GCSE scores across Wards in London can be explained by variation in unauthorised absence from school (which is quite a lot for a single variable).

Interrogating the last graph in plot(model1)which is a scatter plot of fitted values (the model estimates achieved by plugging the values and coefficients back into the regression equation) against standardised residuals, we can see no apparent patterns in the cloud of points, which suggests the model has not violated any important assumptions.

Test for spatial patterns

we shoud test that is there any spatial clustering of residuals.If these places cluster in space, then there might be some unobserved underlying factor causing this. This is important is it means that the assumption of independence that regression models rely upon might be violated. Now in our case here, there is not a clear violation of spatial independence, but it is certainly hinted at. test for spatial patterns (spatial autocorrelation) using the Moran’s I statistic

### Test for spatial patterns (spatial autocorrelation) using the Moran's I statistic
#copy a new LondonWardSF
LondonWardSF.pattern <- LondonWardSF
LondonWardSF.pattern$model_resids <- model$residuals
LondonWardSF.pattern <- LondonWardSF.pattern[!(is.na(LondonWardSF.pattern$model_resids) ),]
LondonWardSP.pattern <- as(LondonWardSF.pattern,"Spatial")
tmap_mode("view")
tmap mode set to interactive viewing
qtm(LondonWardSF.pattern,fill='model_resids')
Variable "model_resids" contains positive and negative values, so midpoint is set to 0. Set midpoint = NA to show the full spectrum of the color palette.
#library(spdep)
#Calculate the centroids of London wards
centWard <- coordinates(LondonWardSP.pattern)
plot(centWard)

#Generate the spatial weights matrix,using binary matrix of queen's case neighbours
#create neighbours list
library(spdep)
neighbour <- poly2nb(LondonWardSP.pattern,queen=T)
#plot
plot(neighbour,coordinates(centWard),col="red")
plot(LondonWardSP.pattern,add=T)

#create spatial weights object from these weights
SpatialWeight <- nb2listw(neighbour,style="C",zero.policy=T)
#Run moran I test
moran.test(LondonWardSP.pattern@data$model_resids, SpatialWeight,zero.policy=T)

    Moran I test under randomisation

data:  LondonWardSP.pattern@data$model_resids  
weights: SpatialWeight  n reduced by no-neighbour observations
  

Moran I statistic standard deviate = 9.827, p-value < 2.2e-16
alternative hypothesis: greater
sample estimates:
Moran I statistic       Expectation          Variance 
     0.2252039018     -0.0015923567      0.0005326405 

so here we have a statistically significant but relatively weak indication that there is some spatial clustering of residual values. A value of 0.07 (1 being perfect spatial autocorrelation, 0 being none at all) shows that there is no evidence that high residual values cluster near high values and low residual values cluster near lower values.

multi linear regression model

###For a deeper research, we will build a multiple linear regression model to find whether the urban vitality index has a relationship with urban vitality sub-factors. If so, which one is the strongest or weakest.
#
library(corrplot)
cormat <- cor(node.index.frame[,c(5:8,16)], use="complete.obs", method="pearson")
corrplot(cormat)

#rRun multiple regression model
model_multi <- lm(PointPerSK ~ MixIndex.normalization+Density.normalization + access.mean + EcoAct.normalization, data = node.index.frame)
summary(model_multi)

Call:
lm(formula = PointPerSK ~ MixIndex.normalization + Density.normalization + 
    access.mean + EcoAct.normalization, data = node.index.frame)

Residuals:
    Min      1Q  Median      3Q     Max 
-62.704 -15.816  -3.713  12.011 218.380 

Coefficients:
                       Estimate Std. Error t value Pr(>|t|)    
(Intercept)              26.098      5.856   4.457 9.86e-06 ***
MixIndex.normalization   16.078      7.086   2.269 0.023615 *  
Density.normalization   150.627      6.213  24.245  < 2e-16 ***
access.mean              26.792      7.021   3.816 0.000149 ***
EcoAct.normalization      8.127      6.392   1.271 0.204039    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 26.27 on 625 degrees of freedom
Multiple R-squared:  0.5611,    Adjusted R-squared:  0.5583 
F-statistic: 199.8 on 4 and 625 DF,  p-value: < 2.2e-16
summary(model_multi)

Call:
lm(formula = PointPerSK ~ MixIndex.normalization + Density.normalization + 
    access.mean + EcoAct.normalization, data = node.index.frame)

Residuals:
    Min      1Q  Median      3Q     Max 
-62.704 -15.816  -3.713  12.011 218.380 

Coefficients:
                       Estimate Std. Error t value Pr(>|t|)    
(Intercept)              26.098      5.856   4.457 9.86e-06 ***
MixIndex.normalization   16.078      7.086   2.269 0.023615 *  
Density.normalization   150.627      6.213  24.245  < 2e-16 ***
access.mean              26.792      7.021   3.816 0.000149 ***
EcoAct.normalization      8.127      6.392   1.271 0.204039    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 26.27 on 625 degrees of freedom
Multiple R-squared:  0.5611,    Adjusted R-squared:  0.5583 
F-statistic: 199.8 on 4 and 625 DF,  p-value: < 2.2e-16
LS0tDQp0aXRsZTogIlIgTm90ZWJvb2siDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQpUaGlzIGlzIGFuIFtSIE1hcmtkb3duXShodHRwOi8vcm1hcmtkb3duLnJzdHVkaW8uY29tKSBOb3RlYm9vay4gV2hlbiB5b3UgZXhlY3V0ZSBjb2RlIHdpdGhpbiB0aGUgbm90ZWJvb2ssIHRoZSByZXN1bHRzIGFwcGVhciBiZW5lYXRoIHRoZSBjb2RlLiANCg0KVHJ5IGV4ZWN1dGluZyB0aGlzIGNodW5rIGJ5IGNsaWNraW5nIHRoZSAqUnVuKiBidXR0b24gd2l0aGluIHRoZSBjaHVuayBvciBieSBwbGFjaW5nIHlvdXIgY3Vyc29yIGluc2lkZSBpdCBhbmQgcHJlc3NpbmcgKkN0cmwrU2hpZnQrRW50ZXIqLiANCg0KYGBge3J9DQpsaWJyYXJ5KHNwYXRzdGF0KQ0KbGlicmFyeShzcCkNCmxpYnJhcnkocmdlb3MpDQpsaWJyYXJ5KG1hcHRvb2xzKQ0KbGlicmFyeShHSVNUb29scykNCmluc3RhbGwucGFja2FnZXMoInRpZHl2ZXJzZSIpDQpsaWJyYXJ5KHRtYXApDQpsaWJyYXJ5KHNmKQ0KbGlicmFyeShnZW9qc29uaW8pDQpsaWJyYXJ5KHRtYXB0b29scykNCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShyZ2RhbCkNCmxpYnJhcnkocmFzdGVyKQ0KbGlicmFyeShTY2lWaWV3cykNCmxpYnJhcnkoYmFzZSkNCmxpYnJhcnkoYnJvb20pDQpsaWJyYXJ5KHNwZGVwKQ0KYGBgDQoNCg0KYGBge3J9DQojIyMjQmFzZW1hcA0KbGlicmFyeSh0bWFwKQ0KQm9yb3VnaE1hcCA8LSBnZW9qc29uX3JlYWQoImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9mdC1pbnRlcmFjdGl2ZS9nZW8tZGF0YS9tYXN0ZXIvdWsvbG9uZG9uL2xvbmRvbi13YXJkcy0yMDE0Lmdlb2pzb24iLCB3aGF0ID0gInNwIikNCkJORyA9ICIraW5pdD1lcHNnOjI3NzAwIg0KQm9yb3VnaE1hcEJORyA8LSBzcFRyYW5zZm9ybShCb3JvdWdoTWFwLEJORykNCldHUyA9ICIraW5pdD1lcHNnOjQzMjYiDQp0bWFwX21vZGUoInZpZXciKQ0KdG1fc2hhcGUoQm9yb3VnaE1hcEJORykgK3RtX3BvbHlnb25zKGNvbCA9IE5BLCBhbHBoYSA9IDAuNSkNCg0KI2FnZ3JlZ2F0ZSBjaXR5IG9mIGxvbmRvbiANCmxpYnJhcnkoc2YpDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShyZ2RhbCkNCkJvcm91Z2hNYXBTRiA8LSBzdF9hc19zZihCb3JvdWdoTWFwQk5HKQ0KbGlicmFyeShyZ2VvcykNCkNpdHlvZkxvbmRvbjwtIGdVbmlvbkNhc2NhZGVkKEJvcm91Z2hNYXBCTkdbYyg2MzA6NjU0KSwgXSkNCnBsb3QoQ2l0eW9mTG9uZG9uKQ0KQ2l0eW9mTG9uZG9uU0YgPC0gc3RfYXNfc2YoQ2l0eW9mTG9uZG9uKQ0KQ2l0eW9mTG9uZG9uU0YkZ3NzX2NvZGVfd2FyZDwtIkUwNTAwMDAwMSIgICMjYWRkIHNhbWUgY29sdW1ucyBpbiBjaXR5IG9mIGxvbmRvbiwgZm9yIGFnZ3JlZ2F0aW5nIHdpdGggb3RoZXIgYm9yb3VnaA0KQ2l0eW9mTG9uZG9uU0YkZ3NzX2NvZGVfYm9yb3VnaCA8LSAiRTA5MDAwMDAxIg0KQ2l0eW9mTG9uZG9uU0YkYm9yb3VnaCA8LSJDaXR5IE9mIExvbmRvbiINCkNpdHlvZkxvbmRvblNGJHdhcmQgPC0gIkNpdHkgT2YgTG9uZG9uIg0KQm9yb3VnaE1hcFNGbmV3IDwtIEJvcm91Z2hNYXBTRlstYyg2MzA6NjU0KSwgXQ0KTG9uZG9uV2FyZFNGIDwtIHJiaW5kKEJvcm91Z2hNYXBTRm5ldyxDaXR5b2ZMb25kb25TRikgIyNBdHRlbnRpb24gTmV3IG5vdCBuZXcNCkxvbmRvbldhcmQgPC0gYXMoTG9uZG9uV2FyZFNGLCJTcGF0aWFsIikNCnJvd25hbWVzKExvbmRvbldhcmRTRikgPC0gMTpucm93KExvbmRvbldhcmRTRikNCnRtYXBfbW9kZSgidmlldyIpDQp0bV9zaGFwZShMb25kb25XYXJkKSArdG1fcG9seWdvbnMoY29sID0gTkEsIGFscGhhID0gMC41KSMrdG1fdGV4dCgid2FyZCIsc2l6ZT0wLjMsIGNvbD0iYmxhY2siKSANCg0KDQpgYGANCg0KYGBge3J9DQojIyMjcG9wdWxhdGlvbiBkZW5zaXR5ICh1c2luZyBodHRwczovL2RhdGEubG9uZG9uLmdvdi51ay9kYXRhc2V0L2xhbmQtYXJlYS1hbmQtcG9wdWxhdGlvbi1kZW5zaXR5LXdhcmQtYW5kLWJvcm91Z2ggMjAxNikNCmxpYnJhcnkodGlkeXZlcnNlKQ0KRGVuc2l0eSA8LSByZWFkX2NzdigiRTovVUNMLzAwNS1HSSBTeXN0ZW0mU2NpZW5jZS9HSVMtQXNzZXNzbWVudCAzL1IgYXNzZXNzbWVudDMvcG9wdWxhdGlvbl9kZW5zaXR5XzIwMTZfZmluYWwuY3N2IixuYSA9ICJuL2EiKQ0KI25vcm1hbGl6YXRpb24gcG9wdWxhdGlvbl9wZXJfc3F1YXJlX2ttDQpub3JtYWxpemF0aW9uPC1mdW5jdGlvbih4KXsNCnJldHVybigoeC1taW4oeCkpLyhtYXgoeCktbWluKHgpKSl9DQpkZW5zaXR5Lm5vcm1hbGl6YXRpb24gPC0gbm9ybWFsaXphdGlvbihEZW5zaXR5JGBwb3B1bGF0aW9uIGRlbnNpdHlgKQ0KRGVuc2l0eSREZW5zaXR5Lm5vcm1hbGl6YXRpb24gPC0gZGVuc2l0eS5ub3JtYWxpemF0aW9uDQoNCiNqb2luIHRoZSBkYXRhIHRvIGJhc2VtYXAgUDNQMjcNCkxvbmRvbldhcmQuam9pbi5wb3BkZW5zIDwtIExvbmRvbldhcmRTRiU+JSBsZWZ0X2pvaW4oRGVuc2l0eSxieT1jKCJnc3NfY29kZV93YXJkIj0iTmV3IENvZGUiKSkNCnRtYXBfbW9kZSgidmlldyIpDQpxdG0oTG9uZG9uV2FyZC5qb2luLnBvcGRlbnMsZmlsbD0iRGVuc2l0eS5ub3JtYWxpemF0aW9uIikNCmBgYA0KDQoNCg0KYGBge3J9DQojIyMgUHVibGljIHRyYW5zcG9ydCBhY2Nlc3NpYmlsaXR5IGxldmVsKFBUQUwpDQpQVEFMIDwtIHJlYWRfY3N2KCJFOi9VQ0wvMDA1LUdJIFN5c3RlbSZTY2llbmNlL0dJUy1Bc3Nlc3NtZW50IDMvUiBhc3Nlc3NtZW50My9XYXJkMjAxNCBBdnB1YmxpYyB0cmFuc3BvcnQgYWNjZXNzaWJpbGl0eSBsZXZlbDIwMTUuY3N2IixuYSA9ICJuL2EiKQ0KI25vcm1hbGl6YXRpb24gUFRBTA0Kbm9ybWFsaXphdGlvbjwtZnVuY3Rpb24oeCl7DQpyZXR1cm4oKHgtbWluKHgpKS8obWF4KHgpLW1pbih4KSkpfQ0KUFRBTC5ub3JtYWxpemF0aW9uIDwtIG5vcm1hbGl6YXRpb24oUFRBTCRBdlBUQUkyMDE1KQ0KUFRBTCRQVEFMLm5vcm1hbGl6YXRpb24gPC0gUFRBTC5ub3JtYWxpemF0aW9uDQojam9pbiB0aGUgZGF0YSB0byBiYXNlbWFwIFAzUDI3DQpMb25kb25XYXJkLmpvaW4uUFRBTCA8LSBMb25kb25XYXJkU0YlPiUgbGVmdF9qb2luKFBUQUwsYnk9YygiZ3NzX2NvZGVfd2FyZCI9IldhcmQgQ29kZSIpKQ0KcXRtKExvbmRvbldhcmQuam9pbi5QVEFMLGZpbGw9IlBUQUwubm9ybWFsaXphdGlvbiIpDQpxdG0oTG9uZG9uV2FyZC5qb2luLlBUQUwsZmlsbD0iQXZQVEFJMjAxNSIpDQoNCiMjI1B1YmxpYyBvcGVuIHNwYWNlIGFjY2Vzc2liaWxpdHkgbGV2ZWwoUE9TQUwpDQpQT1NBTCA8LSByZWFkX2NzdigiRTovVUNMLzAwNS1HSSBTeXN0ZW0mU2NpZW5jZS9HSVMtQXNzZXNzbWVudCAzL1IgYXNzZXNzbWVudDMvYWNjZXNzX3B1YmxpY19vcGVuX3NwYWNlX3dhcmQuY3N2IixuYSA9ICJuL2EiKQ0KUE9TQUwkUE9TQUwubm9ybWFsaXphdGlvbiA8LSBub3JtYWxpemF0aW9uKFBPU0FMJGBPcGVuIFNwYWNlYCkNCkxvbmRvbldhcmQuam9pbi5QT1NBTCA8LSBMb25kb25XYXJkU0YlPiUgbGVmdF9qb2luKFBPU0FMLGJ5PWMoImdzc19jb2RlX3dhcmQiPSJXRDEzQ0QiKSkNCiNxdG0oTG9uZG9uV2FyZC5qb2luLlBPU0FMLGZpbGw9IlBPU0FMLm5vcm1hbGl6YXRpb24iKQ0KI2NvbWJpbmUgdHdvIGFjY2Vzc2liaWxpdHkgc3ViLWluZGV4DQpBY2Nlc3Mubm9ybWFsaXphdGlvbjwtIG1lcmdlKFBPU0FMLFBUQUwsIGJ5Lng9IldEMTNDRCIsYnkueT0iV2FyZCBDb2RlIixhbGw9VFJVRSkNCiNyZW1vdmUgdXNlbGVzcyBjb2x1bW4gYW5kIHJvd3MNCkFjY2Vzcy5ub3JtYWxpemF0aW9uWyxjKDQ6OCwxMDoxMSldIDwtIE5VTEwNCiNjYWxjdWxhdGUgdGhlIG1lYW4gb2YgdHdvIGFjY2Vzc2liaWxpdHkgbGV2ZWwNCkFjY2Vzcy5ub3JtYWxpemF0aW9uJGFjY2Vzcy5tZWFuIDwtIHJvd01lYW5zKEFjY2Vzcy5ub3JtYWxpemF0aW9uW2MoJ1BUQUwubm9ybWFsaXphdGlvbicsICdQT1NBTC5ub3JtYWxpemF0aW9uJyldLCBuYS5ybT1UUlVFKQ0KYGBgDQoNCm5vZGUNCmBgYHtyfQ0KIyMjIFJvYWQgaW50ZXJzZWN0aW9ucw0Kbm9kZSA8LSByZWFkT0dSKCJFOi9VQ0wvMDA1LUdJIFN5c3RlbSZTY2llbmNlL0dJUy1Bc3Nlc3NtZW50IDMvUiBhc3Nlc3NtZW50My9Sb2FkIE5ldHdvcmtvcHJvYWRfZXNzaF9nYi9uZXdfcm9hZF9ub2RlLnNocCIsbGF5ZXI9Im5ld19yb2FkX25vZGUiKQ0KQk5HID0gIitpbml0PWVwc2c6Mjc3MDAiDQpub2RlQk5HIDwtIHNwVHJhbnNmb3JtKG5vZGUsIEJORykNCnN1bW1hcnkobm9kZSkNCiMjcXRtKG5vZGVCTkcpDQpub2RlQk5HU0YgPC0gc3RfYXNfc2Yobm9kZUJORykNCiNzZWxlY3QgdGhlIG5vZGUgdHlwZSJqdW5jdGlvbiINCm5vZGVCTkdTRiA8LSBub2RlQk5HU0Zbd2hpY2gobm9kZUJOR1NGJGZvcm1PZk5vZGU9PSJqdW5jdGlvbiIpLF0NCm5vZGVCTkdTUCA8LSBhcyhub2RlQk5HU0YsICJTcGF0aWFsIikNCmhlYWQobm9kZSkNCiNzZWxlY3Qgbm9kZSBwb2ludCBpbiBib3JvdWdoDQpub2RlQk5HU1AgPC0gcmVtb3ZlLmR1cGxpY2F0ZXMobm9kZUJOR1NQKQ0Kbm9kZUJOR1NQLmZpbmFsPC0gbm9kZUJOR1NQW0xvbmRvbldhcmQsXQ0KIyB0bWFwIHZpZXcNCiN0bWFwX21vZGUoInZpZXciKQ0KI3RtX3NoYXBlKExvbmRvbldhcmQpICsNCiMgIHRtX3BvbHlnb25zKGNvbCA9IE5BLCBhbHBoYSA9IDAuNSkgKw0KI3RtX3NoYXBlKG5vZGVCTkdTUC5maW5hbCkgKw0KIyAgdG1fZG90cyhjb2wgPSAiYmx1ZSIpDQoNCiMgY291bnQgbnVtYmVyIG9mIHBvaW50IGluIGVhY2ggd2FyZCANCmxpYnJhcnkoR0lTVG9vbHMpDQpwb2x5LmNvdW50cyhub2RlQk5HU1AuZmluYWwsIExvbmRvbldhcmQpIC0+IG5vZGVjb3VudA0KIyNzZXROYW1lcyhub2RlY291bnQsIExvbmRvbldhcmRAZGF0YSRub2RlY291bnQpDQpMb25kb24ubm9kZSA8LSBMb25kb25XYXJkU0YNCkxvbmRvbi5ub2RlJG5vZGVjb3VudCA8LSBub2RlY291bnQgICAjYWRkIG51bWJlciBvZiBwb2ludCB0byBlYWNoIHdhcmQgKExvbmRvbi5ub2RlJG5vZGVjb3VudCkNCiNjb21iaW5lIHRoZSB3YXJkIGFyZWEoc3Ega20pDQpMb25kb24ubm9kZSRTcXVhcmVfS2lsb21ldHJlcyA8LSBMb25kb25XYXJkLmpvaW4ucG9wZGVucyRgU3F1YXJlIEtpbG9tZXRyZXNgDQojY2FsY3VsYXRlIHBvaW50L2FyZWEtLXBvaW50IHBlciBzcXVhcmUga2lsb21ldHJlDQpMb25kb24ubm9kZSRQb2ludFBlclNLIDwtTG9uZG9uLm5vZGUkbm9kZWNvdW50L0xvbmRvbi5ub2RlJFNxdWFyZV9LaWxvbWV0cmVzDQpxdG0oTG9uZG9uLm5vZGUsZmlsbD0iUG9pbnRQZXJTSyIpDQojam9pbiB3aXRoIExvbmRvbldhcmRTRg0KTG9uZG9uLm5vZGVTRiA8LSBhcHBlbmRfZGF0YShMb25kb25XYXJkU0YsTG9uZG9uLm5vZGUsIGtleS5zaHAgPSAiY29kZSIsIGtleS5kYXRhID0gImdzc19jb2RlX3dhcmQiLCBpZ25vcmUuZHVwbGljYXRlcyA9IFRSVUUpDQpgYGANCg0KZWNvbm9taWMgdml0YWxpdHkNCmBgYHtyfQ0KIyMjZWNvbm9taWMgdml0YWxpdHkNCiNDTEFTUyAxICBob3VzZSBwcmljZQ0KI0hvdXNlUHJpY2UgPC0gcmVhZF9jc3YoIkU6L1VDTC8wMDUtR0kgU3lzdGVtJlNjaWVuY2UvR0lTLUFzc2Vzc21lbnQgMy9SIGFzc2Vzc21lbnQzL2hvdXNlX3ByaWNlX21lYW4yMDE2LmNzdiIsbmEgPSAibi9hIikNCiNIb3VzZVByaWNlLm5vcm1hbGl6YXRpb24gPC0gbm9ybWFsaXphdGlvbihIb3VzZVByaWNlJFZhbHVlKQ0KI0hvdXNlUHJpY2UkSG91c2VQcmljZS5ub3JtYWxpemF0aW9uIDwtIEhvdXNlUHJpY2Uubm9ybWFsaXphdGlvbg0KI0NMQVNTIDIgZWNvbm9taWMgYWN0aXZpdHkNCkVjb0FjdCA8LSByZWFkX2NzdigiRTovVUNMLzAwNS1HSSBTeXN0ZW0mU2NpZW5jZS9HSVMtQXNzZXNzbWVudCAzL1IgYXNzZXNzbWVudDMvZWNvbm9taWNfYWN0aXZpdHlfd2FyZC5jc3YiLG5hID0gIm4vYSIpDQpFY29BY3Qubm9ybWFsaXphdGlvbiA8LSBub3JtYWxpemF0aW9uKEVjb0FjdCRgRWNvbm9taWNhbGx5IGFjdGl2ZTogVG90YWxgKQ0KRWNvQWN0JEVjb0FjdC5ub3JtYWxpemF0aW9uIDwtIEVjb0FjdC5ub3JtYWxpemF0aW9uDQoNCmBgYA0KDQpsYW5kIHVzZSBtaXgNCmBgYHtyfQ0KIyMjIExhbmQgdXNlIG1peA0KI2h0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL1BsYW5uaW5nX3VzZV9jbGFzc2VzX2luX0VuZ2xhbmQgDQojIHNpeCBjbGFzc2VzLS0NCmxhbmRjb3ZlciA8LSByZWFkT0dSKCJFOi9VQ0wvMDA1LUdJIFN5c3RlbSZTY2llbmNlL0dJUy1Bc3Nlc3NtZW50IDMvUiBhc3Nlc3NtZW50My9ncmVhdGVyLWxvbmRvbi1sYXRlc3QtZnJlZS5zaHAvZ2lzX29zbV9sYW5kdXNlX2FfZnJlZV8xLnNocCIsbGF5ZXI9Imdpc19vc21fbGFuZHVzZV9hX2ZyZWVfMSIpDQpsYW5kY292ZXJCTkcgPC0gc3BUcmFuc2Zvcm0obGFuZGNvdmVyLCBCTkcpDQpsYW5kY292ZXJCTkdTRiA8LSBzdF9hc19zZihsYW5kY292ZXJCTkcpDQoNCkFPSVMgPC0gcmVhZE9HUigiRTovVUNMLzAwNS1HSSBTeXN0ZW0mU2NpZW5jZS9HSVMtQXNzZXNzbWVudCAzL1IgYXNzZXNzbWVudDMvZ3JlYXRlci1sb25kb24tbGF0ZXN0LWZyZWUuc2hwL2dpc19vc21fcG9pc19hX2ZyZWVfMS5zaHAiLGxheWVyPSJnaXNfb3NtX3BvaXNfYV9mcmVlXzEiKQ0KQU9JU0JORyA8LSBzcFRyYW5zZm9ybShBT0lTLCBCTkcpDQpBT0lTQk5HU0YgPC0gc3RfYXNfc2YoQU9JU0JORykNCg0KI2ZpbmQgbWlzc2luZyBkYXRhIGluIGVhY2ggY29sdW1uIGluIGxhbmRjb3ZlckJOR1NGDQpjb2xTdW1zKGlzLm5hKGxhbmRjb3ZlckJOR1NGKSkNCiNnZXQgdGhlIGNsYXNzZXMgb2YgbGFuZGNvdmVyDQpzdW1tYXJ5KGxhbmRjb3ZlckJOR1NGKQ0KI0NMQVNTMSBncmVlbnNwYWNlDQpncmVlbnNwYWNlQk5HU0YgPC0gbGFuZGNvdmVyQk5HU0ZbIHdoaWNoKCBsYW5kY292ZXJCTkdTRiRmY2xhc3MgPT0icGFyayIgfCAgbGFuZGNvdmVyQk5HU0YkZmNsYXNzID09ImZvcmVzdCJ8bGFuZGNvdmVyQk5HU0YkZmNsYXNzID09Im5hdHVyZV9yZXNlcnZlInxsYW5kY292ZXJCTkdTRiRmY2xhc3MgPT0iZ3Jhc3MiKSxdIA0KZ3JlZW5zcGFjZUJOR1NQIDwtIGFzKGdyZWVuc3BhY2VCTkdTRiwiU3BhdGlhbCIpDQojQ0xBU1MyIGluZHVzdHJpYWwgYW5kIGNvbW1lcmNpYWwNCmluZHVzdHJpYWxCTkdTRiA8LSBsYW5kY292ZXJCTkdTRlsgd2hpY2goIGxhbmRjb3ZlckJOR1NGJGZjbGFzcyA9PSJpbmR1c3RyaWFsInwgbGFuZGNvdmVyQk5HU0YkZmNsYXNzID09ImNvbW1lcmNpYWwiKSxdDQppbmR1c3RyaWFsQk5HU1AgPC0gYXMoaW5kdXN0cmlhbEJOR1NGLCJTcGF0aWFsIikNCiNDTEFTUyAzIHJlc2lkZW50aWFsDQpyZXNpZGVudGlhbEJOR1NGIDwtIGxhbmRjb3ZlckJOR1NGWyB3aGljaCggbGFuZGNvdmVyQk5HU0YkZmNsYXNzID09InJlc2lkZW50aWFsIiApLF0NCnJlc2lkZW50aWFsQk5HU1AgPC0gYXMocmVzaWRlbnRpYWxCTkdTRiwiU3BhdGlhbCIpDQojQ0xBU1MgNCByZWNyZWF0aW9uLWxlaXN1cmUNCnJlY3JlYXRpb25CTkdTRjEgPC0gbGFuZGNvdmVyQk5HU0ZbIHdoaWNoKCBsYW5kY292ZXJCTkdTRiRmY2xhc3MgPT0icmVjcmVhdGlvbl9ncm91bmQifCBsYW5kY292ZXJCTkdTRiRmY2xhc3MgPT0iYWxsb3RtZW50cyIpLF0NCnJlY3JlYXRpb25CTkdTRjIgPC0gQU9JU0JOR1NGWyB3aGljaChBT0lTQk5HU0YkZmNsYXNzID09ImF0dHJhY3Rpb24ifEFPSVNCTkdTRiRmY2xhc3MgPT0idGhlYXRyZSJ8QU9JU0JOR1NGJGZjbGFzcyA9PSJhcnRzX2NlbnRyZSIpLF0NCnJlY3JlYXRpb25CTkdTRiA8LSByYmluZChyZWNyZWF0aW9uQk5HU0YyLHJlY3JlYXRpb25CTkdTRjEpDQpyZWNyZWF0aW9uQk5HU1AgPC0gYXMocmVjcmVhdGlvbkJOR1NGLCJTcGF0aWFsIikNCg0KDQojQ0xBU1MgNSByZXRhaWwNCnJldGFpbEJOR1NGMSA8LSBsYW5kY292ZXJCTkdTRlsgd2hpY2goIGxhbmRjb3ZlckJOR1NGJGZjbGFzcyA9PSJyZXRhaWwiICksXQ0KcmV0YWlsQk5HU0YyIDwtIEFPSVNCTkdTRlsgd2hpY2goIEFPSVNCTkdTRiRmY2xhc3MgPT0icmV0YWlsIiApLF0NCnJldGlhbEJOR1NGIDwtIHJiaW5kKHJldGFpbEJOR1NGMixyZXRhaWxCTkdTRjEpDQpyZXRhaWxCTkdTUCA8LSBhcyhyZXRhaWxCTkdTRiwiU3BhdGlhbCIpDQoNCiNDTEFTUyA2LS1jb21tdW5pdHkgc2VydmljZXMNCmNvbW11bml0eUJOR1NGIDwtIEFPSVNCTkdTRlsgd2hpY2goQU9JU0JOR1NGJGZjbGFzcyA9PSJzY2hvb2wifEFPSVNCTkdTRiRmY2xhc3MgPT0iaG9zcGl0YWwifEFPSVNCTkdTRiRmY2xhc3MgPT0ibnVyc2luZ19ob21lInxBT0lTQk5HU0YkZmNsYXNzID09InVuaXZlcnNpdHkiICApLF0NCmNvbW11bml0eUJOR1NQIDwtIGFzKGNvbW11bml0eUJOR1NGLCJTcGF0aWFsIikNCg0KI0NMQVNTIDctLXRyYW5zcG9ydA0KdHJhbnNwb3J0IDwtIHJlYWRPR1IoIkU6L1VDTC8wMDUtR0kgU3lzdGVtJlNjaWVuY2UvR0lTLUFzc2Vzc21lbnQgMy9SIGFzc2Vzc21lbnQzL2dyZWF0ZXItbG9uZG9uLWxhdGVzdC1mcmVlLnNocC9yb2FkX3BvbHlnb25fbWVyZ2Uuc2hwIixsYXllcj0icm9hZF9wb2x5Z29uX21lcmdlIikNCnRyYW5zcG9ydEJORyA8LSBzcFRyYW5zZm9ybSh0cmFuc3BvcnQsIEJORykNCnRyYW5zcG9ydEJORyA8LSB0cmFuc3BvcnRCTkdbdHJhbnNwb3J0Qk5HQGRhdGEkQVJFQSA+MTAwMDAsXSANCg0KDQpgYGANCg0KYGBge3J9DQojIEFzc2lnbiB0aGUgbGFuZCB1c2UgYXJlYSBmb3IgZWFjaCBzdWJzZXQuIEhlcmUgd2UgZmlyc3QgdXNlIHRoZSBtb3N0IHdpZGVzcHJlYWQgcmVzaWRlbnRpYWwgYXMgZXhhbXBsZSANCmxpYnJhcnkocmFzdGVyKQ0KciA8LSByYXN0ZXIobmNvbHM9NDAwLCBucm93cz00MDApICNnZW5lcmF0ZSByYXN0ZXIgc2l6ZShxdWFudGl0eSkNCmV4dGVudChyKSA8LSBleHRlbnQocmVzaWRlbnRpYWxCTkdTUCkgICNJbXBvcnRhbnQhIEFzc2lnbiB0aGUgZXh0ZW50IG9mIHJhc3RlciB0byBjb3ZlciB0aGUgc2FtZSBleHRlbnRzIG9mIHRoZSBwb2x5Z29uDQpyZXNpZGVudGlhbC5SYXN0ZXIgPC0gcmFzdGVyaXplKHJlc2lkZW50aWFsQk5HU1AscixiYWNrZ3JvdW5kPU5BKSAjY29udmVydCBwb2x5Z29uIHRvIHJhc3Rlcg0KI3RtYXBfbW9kZSgidmlldyIpDQojcXRtKHJlc2lkZW50aWFsLlJhc3RlcikrdG1fc2hhcGUoTG9uZG9uV2FyZCkgK3RtX3BvbHlnb25zKGNvbCA9IE5BLCBhbHBoYSA9IDAuNSkNCiNleHRyYWN0IHJhc3RlcnMgZnJvbSBwb2x5Z29ucyMoZXh0cmFjdCgpIGNhbm5vdCB1c2UgbWV0aG9kPWJpbGluZWFyIGluIHJhc3Rlci1pbi1wb2x5Z29uKQ0KcmVzaWRlbnRpYWwuZXh0cmFjdCA8LSByYXN0ZXI6OmV4dHJhY3QocmVzaWRlbnRpYWwuUmFzdGVyLExvbmRvbldhcmQsZGY9VFJVRSwgd2VpZ2h0cyA9RkFMU0UsIG5hLnJtID0gVFJVRSkNCiNyZW1vdmUgcm93cyB3aXRoIE5BDQpyb3cuaGFzLm5hIDwtIGFwcGx5KHJlc2lkZW50aWFsLmV4dHJhY3QsIDEsIGZ1bmN0aW9uKHgpe2FueShpcy5uYSh4KSl9KQ0KcmVzaWRlbnRpYWwuZXh0cmFjdDIgPC1yZXNpZGVudGlhbC5leHRyYWN0WyFyb3cuaGFzLm5hLF0NCiNtZXJnZSB0aGUgcGl4ZWwgaW4gc2FtZSB3YXJkKGFnZ3JlZ2F0ZSB0aGUgZnJlcXVlbmN5IG9mIHRoZSBzYW1lIGRhdGEgaW4gb25lKQ0KbGlicmFyeShwbHlyKQ0KcmVzaWRlbnRpYWwuZXh0cmFjdC5zdW0gPC0gZmFjdG9yKHJlc2lkZW50aWFsLmV4dHJhY3QyJElEKSAgDQpyZXNpZGVudGlhbC5leHRyYWN0LnN1bSA8LSB0YWJsZShyZXNpZGVudGlhbC5leHRyYWN0MiRJRCkNCnJlc2lkZW50aWFsLmV4dHJhY3Qud2FyZHN1bSA8LSBhcy5kYXRhLmZyYW1lKHJlc2lkZW50aWFsLmV4dHJhY3Quc3VtKQ0KI2NyZWF0ZSBuZXcgb3JkZXIgbnVtYmVyIGZvciBMb25kb25XYXJkU0YsIGZvciBtZXJnZSB0aGUgcmVzaWRlbnRpYWwuZXh0cmFjdCBhbmQgTG9uZG9uV2FyZFNGIGJ5IG9yZGVyDQpMb25kb25XYXJkMlNGIDwtIExvbmRvbldhcmRTRg0KTG9uZG9uV2FyZDJTRiRWYXIxIDwtIDE6NjMwDQpMb25kb25XYXJkMlNGWywnVmFyMSddPC1mYWN0b3IoTG9uZG9uV2FyZDJTRlssJ1ZhcjEnXSkNCiNtZXJnZSB0d28gZGF0YWZyYW1lDQpyZXNpZGVudGlhbC5leHRyYWN0LmZpbmFsIDwtIG1lcmdlKHJlc2lkZW50aWFsLmV4dHJhY3Qud2FyZHN1bSwgTG9uZG9uV2FyZDJTRiwgYnk9IlZhcjEiLGFsbD1UUlVFKQ0KI3Jlc2lkZW50aWFsLmV4dHJhY3QuZmluYWwgWyFkdXBsaWNhdGVkKHJlc2lkZW50aWFsLmV4dHJhY3QuZmluYWwgKSwgXQ0KI3JlcGxhY2UgTkEgdmFsdWVzIHdpdGggMA0KcmVzaWRlbnRpYWwuZXh0cmFjdC5maW5hbFtpcy5uYShyZXNpZGVudGlhbC5leHRyYWN0LmZpbmFsKV0gPC0gMA0KI3JlbmFtZSB0aGUgY29sdW1uDQpjb2xuYW1lcyhyZXNpZGVudGlhbC5leHRyYWN0LmZpbmFsKVsyXSA8LSAiRnJlcS5yZXNpZGVudGlhbCINCiNyYXN0ZXIgY2VsbCBzaXplDQojd2UgaGF2ZSB0byBjb252ZXJ0IHJhc3RlciB0byBwb2x5Z29uIGJlY2F1c2Ugb2YgcmFzdGVyKCkuIFRoaXMgZnVuY3Rpb24gb25seSBjb21wdXRlIHRoZSBwaXhlbCBhcmVhIGluIGxvbmdpdHVkZS9sYXRpdHVkZSBjb29yZGlhbnRlIHN5c3RlbQ0KcmVzaWRlbnRpYWwucmVwb2x5Z29uIDwtIHJhc3RlclRvUG9seWdvbnMocmVzaWRlbnRpYWwuUmFzdGVyLCBmdW49TlVMTCwgbj00LCBuYS5ybT1UUlVFLCBkaWdpdHM9MTIsIGRpc3NvbHZlPVRSVUUpDQojcXRtKHJlc2lkZW50aWFsLnJlcG9seWdvbikNCnJlc2lkZW50aWFsLnJlcG9seWdvblNGIDwtIHN0X2FzX3NmKHJlc2lkZW50aWFsLnJlcG9seWdvbikgDQpyZXNpZGVudGlhbC5yZXBvbHlnb25TRiRhcmVhIDwtIHN0X2FyZWEocmVzaWRlbnRpYWwucmVwb2x5Z29uU0YpDQojc28gdGhlIHNpbmdsZSBwaXhlbCBhcmVhIGlzIDI4OTk5LjU0IFttXjJdKDAuMDI5IGttXjIpDQoNCmBgYA0KDQpsYW5kIHVzZSBtaXggZnVuY3Rpb25zDQpgYGB7cn0NCiMjYmFzZWQgb24gdGhlIGRldGFpbHMgYWJvdmUsIHdlIGNyZWF0ZSBmdW5jdGlvbnMgZm9yIGxhbmQgdXNlIGFuYWx5c2lzDQpmdW5jdGlvbi5yYXN0ZXIgPC0gZnVuY3Rpb24obGFuZHNwKXsNCiAgZXh0ZW50KHIpIDwtIGV4dGVudChsYW5kc3ApDQogIGxhbmRzcC5SYXN0ZXIgPC0gcmFzdGVyaXplKGxhbmRzcCxyLGJhY2tncm91bmQ9TkEpDQogIHJldHVybihsYW5kc3AuUmFzdGVyKQ0KfQ0KDQpmdW5jdGlvbi5leHRyYWN0PC0gZnVuY3Rpb24obGFuZHNwLlJhc3Rlcil7DQogIGxhbmRzcC5leHRyYWN0IDwtIHJhc3Rlcjo6ZXh0cmFjdChsYW5kc3AuUmFzdGVyLExvbmRvbldhcmQsZGY9VFJVRSwgd2VpZ2h0cyA9RkFMU0UsIG5hLnJtID0gVFJVRSkNCiAgcm93Lmhhcy5uYSA8LSBhcHBseShsYW5kc3AuZXh0cmFjdCwgMSwgZnVuY3Rpb24oeCl7YW55KGlzLm5hKHgpKX0pDQogIGxhbmRzcC5leHRyYWN0MiA8LWxhbmRzcC5leHRyYWN0WyFyb3cuaGFzLm5hLF0NCiAgbGFuZHNwLmV4dHJhY3Quc3VtIDwtIGZhY3RvcihsYW5kc3AuZXh0cmFjdDIkSUQpICANCiAgbGFuZHNwLmV4dHJhY3Quc3VtIDwtIHRhYmxlKGxhbmRzcC5leHRyYWN0MiRJRCkNCiAgbGFuZHNwLmV4dHJhY3Qud2FyZHN1bSA8LSBhcy5kYXRhLmZyYW1lKGxhbmRzcC5leHRyYWN0LnN1bSkNCiAgbGFuZHNwLmV4dHJhY3QuZmluYWwgPC0gbWVyZ2UobGFuZHNwLmV4dHJhY3Qud2FyZHN1bSwgTG9uZG9uV2FyZDJTRiwgYnk9IlZhcjEiLGFsbD1UUlVFKQ0KICBsYW5kc3AuZXh0cmFjdC5maW5hbFtpcy5uYShsYW5kc3AuZXh0cmFjdC5maW5hbCldIDwtIDANCiAgcmV0dXJuKGxhbmRzcC5leHRyYWN0LmZpbmFsKQ0KfQ0KYGBgDQoNCmBgYHtyfQ0KI2dyZWVuIHNwYWNlIHJhc3Rlcg0KZ3JlZW5zcGFjZS5SYXN0ZXIgPC0gZnVuY3Rpb24ucmFzdGVyKGdyZWVuc3BhY2VCTkdTUCkNCmdyZWVuc3BhY2UuZXh0cmFjdC5maW5hbCA8LSBmdW50aW9uLmV4dHJhY3QoZ3JlZW5zcGFjZS5SYXN0ZXIpDQpjb2xuYW1lcyhncmVlbnNwYWNlLmV4dHJhY3QuZmluYWwpWzJdIDwtICJGcmVxLmdyZWVuc3BhY2UiDQoNCiNpbmR1c3RyaWFsIGFuZCBjb21tZXJjaWFsDQppbmR1c3RyaWFsLlJhc3RlciA8LSBmdW5jdGlvbi5yYXN0ZXIoaW5kdXN0cmlhbEJOR1NQKQ0KaW5kdXN0cmlhbC5leHRyYWN0LmZpbmFsIDwtIGZ1bmN0aW9uLmV4dHJhY3QoaW5kdXN0cmlhbC5SYXN0ZXIpDQpjb2xuYW1lcyhpbmR1c3RyaWFsLmV4dHJhY3QuZmluYWwpWzJdIDwtICJGcmVxLmluZHVzdHJpYWwiDQojcmVjcmVhdGlvbg0KcmVjcmVhdGlvbi5SYXN0ZXIgPC0gZnVuY3Rpb24ucmFzdGVyKHJlY3JlYXRpb25CTkdTUCkNCnJlY3JlYXRpb24uZXh0cmFjdC5maW5hbCA8LSBmdW5jdGlvbi5leHRyYWN0KHJlY3JlYXRpb24uUmFzdGVyKQ0KY29sbmFtZXMocmVjcmVhdGlvbi5leHRyYWN0LmZpbmFsKVsyXSA8LSAiRnJlcS5yZWNyZWF0aW9uIg0KI3JldGFpbA0KcmV0YWlsLlJhc3RlciA8LSBmdW5jdGlvbi5yYXN0ZXIocmVjcmVhdGlvbkJOR1NQKQ0KcmV0YWlsLmV4dHJhY3QuZmluYWwgPC0gZnVuY3Rpb24uZXh0cmFjdChyZXRhaWwuUmFzdGVyKQ0KY29sbmFtZXMocmV0YWlsLmV4dHJhY3QuZmluYWwpWzJdIDwtICJGcmVxLnJldGFpbCINCiNjb21tdW5pdHkNCmNvbW11bml0eS5SYXN0ZXIgPC0gZnVuY3Rpb24ucmFzdGVyKGNvbW11bml0eUJOR1NQKQ0KY29tbXVuaXR5LmV4dHJhY3QuZmluYWwgPC0gZnVuY3Rpb24uZXh0cmFjdChjb21tdW5pdHkuUmFzdGVyKQ0KY29sbmFtZXMoY29tbXVuaXR5LmV4dHJhY3QuZmluYWwpWzJdIDwtICJGcmVxLmNvbW11bml0eSINCiN0cmFuc3BvcnQNCnRyYW5zcG9ydC5SYXN0ZXIgPC0gZnVuY3Rpb24ucmFzdGVyKHRyYW5zcG9ydEJORykNCnRyYW5zcG9ydC5leHRyYWN0LmZpbmFsIDwtIGZ1bmN0aW9uLmV4dHJhY3QodHJhbnNwb3J0LlJhc3RlcikNCmNvbG5hbWVzKHRyYW5zcG9ydC5leHRyYWN0LmZpbmFsKVsyXSA8LSAiRnJlcS50cmFuc3BvcnQiDQoNCnRtYXBfbW9kZSgidmlldyIpDQp0bV9zaGFwZShMb25kb25XYXJkKSArdG1fcG9seWdvbnMoY29sID0gTkEsIGFscGhhID0gMC4yKStxdG0ocmVjcmVhdGlvbi5SYXN0ZXIpDQojdG1fc2hhcGUoTG9uZG9uV2FyZCkgK3RtX3BvbHlnb25zKGNvbCA9IE5BLCBhbHBoYSA9IDAuMikrcXRtKHJlc2lkZW50aWFsLlJhc3RlcikNCg0KI2V4dHJhY3QgdXNlZnVsIGNvbHVtbnMgZnJvbSBtdWx0aXBsZSBkYXRhZnJhbWUNCmxhbmR1c2UuZGF0YWZyYW1lIDwtIHJlc2lkZW50aWFsLmV4dHJhY3QuZmluYWwNCmxhbmR1c2UuZGF0YWZyYW1lIDwtIG1lcmdlKGxhbmR1c2UuZGF0YWZyYW1lLGdyZWVuc3BhY2UuZXh0cmFjdC5maW5hbCwgYnk9IlZhcjEiLGFsbD1UUlVFKQ0KbGFuZHVzZS5kYXRhZnJhbWUgPC0gbWVyZ2UobGFuZHVzZS5kYXRhZnJhbWUsaW5kdXN0cmlhbC5leHRyYWN0LmZpbmFsLCBieT0iVmFyMSIsYWxsPVRSVUUpDQpsYW5kdXNlLmRhdGFmcmFtZSA8LSBtZXJnZShsYW5kdXNlLmRhdGFmcmFtZSxyZWNyZWF0aW9uLmV4dHJhY3QuZmluYWwsIGJ5PSJWYXIxIixhbGw9VFJVRSkNCmxhbmR1c2UuZGF0YWZyYW1lIDwtIG1lcmdlKGxhbmR1c2UuZGF0YWZyYW1lLHJldGFpbC5leHRyYWN0LmZpbmFsLCBieT0iVmFyMSIsYWxsPVRSVUUpDQpsYW5kdXNlLmRhdGFmcmFtZSA8LSBtZXJnZShsYW5kdXNlLmRhdGFmcmFtZSxjb21tdW5pdHkuZXh0cmFjdC5maW5hbCwgYnk9IlZhcjEiLGFsbD1UUlVFKQ0KbGFuZHVzZS5kYXRhZnJhbWUgPC0gbWVyZ2UobGFuZHVzZS5kYXRhZnJhbWUsdHJhbnNwb3J0LmV4dHJhY3QuZmluYWwsIGJ5PSJWYXIxIixhbGw9VFJVRSkNCmxhbmR1c2UuZGF0YWZyYW1lWyxjKDk6MTMsMTU6MTksMjE6MjUsMjc6MzEsMzM6MzcsMzk6NDMpXSA8LSBOVUxMICNyZW1vdmUgdXNlbGVzcyBjb2x1bW4NCmNvbG5hbWVzKGxhbmR1c2UuZGF0YWZyYW1lKVsyXSA8LSAicmVzaWRlbnRpYWwuZnJlcSIgI3JlbmFtZSBjb2x1bW4NCmhlYWQobGFuZHVzZS5kYXRhZnJhbWUpDQoNCg0KYGBgDQoNCmBgYHtyfQ0KDQojY2FsY3VsYXRlIGVhY2ggd2FyZCBhcmVhDQpsYW5kdXNlLmRhdGFmcmFtZVNGIDwtbGVmdF9qb2luKExvbmRvbldhcmRTRixsYW5kdXNlLmRhdGFmcmFtZSxieT1jKCJnc3NfY29kZV93YXJkIj0iZ3NzX2NvZGVfd2FyZC54IikpDQpsYW5kdXNlLmRhdGFmcmFtZVNGJHdhcmRBcmVhIDwtIHN0X2FyZWEobGFuZHVzZS5kYXRhZnJhbWVTRikNCg0KbGlicmFyeShTY2lWaWV3cykNCmZ1bmN0aW9uLmxhbmR1c2VtaXggPC0gZnVuY3Rpb24obGFuZHVzZWZyZXEpew0KICBsYW5kdXNlYXJlYSA8LSBsYW5kdXNlZnJlcSooMC4wMjkqMC4wMjkpDQogIGxhbmR1c2VQZXJjZW50IDwtIGxhbmR1c2VhcmVhL2xhbmR1c2UuZGF0YWZyYW1lU0Ykd2FyZEFyZWENCiAgTFVNIDwtIGxhbmR1c2VQZXJjZW50KmxuKGxhbmR1c2VQZXJjZW50KQ0KICByZXR1cm4oTFVNKQ0KfQ0KDQpsYW5kdXNlLmRhdGFmcmFtZVNGJHJlc2lkZW50aWFsLkxVTSA8LSBmdW5jdGlvbi5sYW5kdXNlbWl4KGxhbmR1c2UuZGF0YWZyYW1lU0YkcmVzaWRlbnRpYWwuZnJlcSkNCmxhbmR1c2UuZGF0YWZyYW1lU0YkZ3JlZW5zcGFjZS5MVU0gPC0gZnVuY3Rpb24ubGFuZHVzZW1peChsYW5kdXNlLmRhdGFmcmFtZVNGJEZyZXEuZ3JlZW5zcGFjZSkNCmxhbmR1c2UuZGF0YWZyYW1lU0YkaW5kdXN0cmlhbC5MVU0gPC0gZnVuY3Rpb24ubGFuZHVzZW1peChsYW5kdXNlLmRhdGFmcmFtZVNGJEZyZXEuaW5kdXN0cmlhbCkNCmxhbmR1c2UuZGF0YWZyYW1lU0YkcmVjcmVhdGlvbi5MVU0gPC0gZnVuY3Rpb24ubGFuZHVzZW1peChsYW5kdXNlLmRhdGFmcmFtZVNGJEZyZXEucmVjcmVhdGlvbikNCmxhbmR1c2UuZGF0YWZyYW1lU0YkcmV0YWlsLkxVTSA8LSBmdW5jdGlvbi5sYW5kdXNlbWl4KGxhbmR1c2UuZGF0YWZyYW1lU0YkRnJlcS5yZXRhaWwpDQpsYW5kdXNlLmRhdGFmcmFtZVNGJGNvbW11bml0eS5MVU0gPC0gZnVuY3Rpb24ubGFuZHVzZW1peChsYW5kdXNlLmRhdGFmcmFtZVNGJEZyZXEuY29tbXVuaXR5KQ0KbGFuZHVzZS5kYXRhZnJhbWVTRiR0cmFuc3BvcnQuTFVNIDwtIGZ1bmN0aW9uLmxhbmR1c2VtaXgobGFuZHVzZS5kYXRhZnJhbWVTRiRGcmVxLnRyYW5zcG9ydCkNCmxpYnJhcnkoYmFzZSkNCiMjI3N1bSBsYW5kdXNlLkxVTSBhbmQgY2FsY3VsYXRlIGluZGV4DQppbmRleC5kYXRhZnJhbWU8LSBzdF9zZXRfZ2VvbWV0cnkobGFuZHVzZS5kYXRhZnJhbWVTRlssYygxOjYsMTg6MjUpXSxOVUxMKQ0KI3JlcGxhY2UgTkFOIHdpdGggMA0KaW5kZXguZGF0YWZyYW1lW2lzLm5hKGluZGV4LmRhdGFmcmFtZSldIDwtIDAgDQojIyNjb21wdXRlIGxhbmQgdXNlIG1peCBpbmRleA0KaW5kZXguZGF0YWZyYW1lJE1peEluZGV4IDwtIChhYnMocm93U3VtcyhpbmRleC5kYXRhZnJhbWVbLDg6MTRdKSkpL2xuKDcpDQojTWl4SW5kZXggbm9ybWFsaXNhdGlvbg0KaW5kZXguZGF0YWZyYW1lJE1peEluZGV4Lm5vcm1hbGl6YXRpb24gPC0gbm9ybWFsaXphdGlvbihpbmRleC5kYXRhZnJhbWUkTWl4SW5kZXggKQ0KcXRtKGluZGV4LmRhdGFmcmFtZVNGLGZpbGw9Ik1peEluZGV4Lm5vcm1hbGl6YXRpb24iKQ0KYGBgDQoNCmBgYHtyfQ0KDQpxdG0ocmVzaWRlbnRpYWwuUmFzdGVyKQ0KbGlicmFyeSh0bWFwKQ0KdG1hcF9tb2RlKCJ2aWV3IikNCnRtX3NoYXBlKExvbmRvbldhcmQpICsNCiAgdG1fcG9seWdvbnMoY29sID0gTkEsIGFscGhhID0gMC41KSArDQp0bV9zaGFwZShyZXNpZGVudGlhbEJOR1NQKSArDQogIHRtX3BvbHlnb25zKGNvbCA9ICJibHVlIikNCmBgYA0KDQpgYGB7cn0NCiMjI2NvbWJpbmUgYWxsIHN1YmluZGV4IA0KaW5kZXguZGF0YWZyYW1lIDwtIG1lcmdlKGluZGV4LmRhdGFmcmFtZSxEZW5zaXR5LGJ5Lng9Imdzc19jb2RlX3dhcmQiLGJ5Lnk9Ik5ldyBDb2RlIixhbGw9VFJVRSkNCiNpbmRleC5kYXRhZnJhbWVbLDM6N10gPC0gTlVMTA0KaW5kZXguZGF0YWZyYW1lIDwtIG1lcmdlKGluZGV4LmRhdGFmcmFtZSxBY2Nlc3Mubm9ybWFsaXphdGlvbiwgYnkueD0iZ3NzX2NvZGVfd2FyZCIsYnkueT0iV0QxM0NEIixhbGw9VFJVRSkNCmluZGV4LmRhdGFmcmFtZSA8LSBtZXJnZShpbmRleC5kYXRhZnJhbWUsRWNvQWN0LCBieS54PSJnc3NfY29kZV93YXJkIixieS55PSJOZXcgQ29kZSIsYWxsPVRSVUUpDQppbmRleC5kYXRhZnJhbWUgPC0gaW5kZXguZGF0YWZyYW1lWyxjKDE6NCwxNiwyMSwyNiwzMCldDQpoZWFkKGluZGV4LmRhdGFmcmFtZSkNCiMjI2NhbGN1bGF0ZSB0aGUgZmluYWwgaW5kZXggb2Ygd2FyZHMsc2V0IHdlaWdodHMNCmZ1bmN0aW9uLnZpdGFsaXR5LmluZGV4IDwtIGZ1bmN0aW9uKHdMYW5kLHdEZW5zaXR5LHdBY2Nlc3Msd0Vjb0FjdCl7DQogIEluZGV4IDwtICh3TGFuZCkqKGluZGV4LmRhdGFmcmFtZVssNV0pKyh3RGVuc2l0eSkqKGluZGV4LmRhdGFmcmFtZVssNl0pKyh3QWNjZXNzKSooaW5kZXguZGF0YWZyYW1lWyw3XSkrKHdFY29BY3QpKihpbmRleC5kYXRhZnJhbWVbLDhdKQ0KICByZXR1cm4oSW5kZXgpDQp9DQojYXNzaWduIHdlaWdodCB0byBlYWNoIHN1YmluZGV4DQppbmRleC5kYXRhZnJhbWUkSW5kZXggPC0gZnVuY3Rpb24udml0YWxpdHkuaW5kZXgoMC40LDAuMywwLjIsMC4xKQ0KI2pvaW4gd2l0aCBMb25kb25XYXJkU0YgYW5kIHZpc3VhbGlzYXRpb24NCmluZGV4LmRhdGFmcmFtZVNGIDwtbGVmdF9qb2luKExvbmRvbldhcmRTRixpbmRleC5kYXRhZnJhbWUsYnk9YygiZ3NzX2NvZGVfd2FyZCI9Imdzc19jb2RlX3dhcmQiKSkNCmluZGV4LmRhdGFmcmFtZVNQIDwtIGFzKGluZGV4LmRhdGFmcmFtZVNGLCAiU3BhdGlhbCIpDQojY3JlYXRlIGluZGV4IGZhY2V0KHVzaW5nIHRtYXApDQp0bWFwX21vZGUoInZpZXciKQ0KdG1fc2hhcGUoaW5kZXguZGF0YWZyYW1lU1AgKSsNCiAgICB0bV9wb2x5Z29ucyhjKCJJbmRleCIsICJNaXhJbmRleC5ub3JtYWxpemF0aW9uIiwiRGVuc2l0eS5ub3JtYWxpemF0aW9uIiwiRWNvQWN0Lm5vcm1hbGl6YXRpb24iLCJhY2Nlc3MubWVhbiIpKSArDQogICAgdG1fZmFjZXRzKHN5bmMgPSBUUlVFLCBuY29sID0gMSxucm93PTUsZHJvcC5lbXB0eS5mYWNldHMgPSBGKQ0KYGBgDQoNCiNUZXN0IGZvciB0aGUgcmVsYXRpb25zaGlwDQojI0xpbmVhciByZWdyZXNzaW9uIG1vZGVsDQoNCmBgYHtyfQ0KIyMjU2luY2Ugd2UgaGF2ZSBkb25lIHRoZSBtb3N0IGltcG9ydGFudCBwYXJ0IG9mIGRhdGEgbWFuaXB1bGF0aW9uLCBuZXh0IHdlIHdpbGwgZXhwbG9yZSB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gaW50ZXJzZWN0aW9uIGFuZCB2aXRhbGl0eQ0KI2hpc3RvZ3JhbSBvZiB0d28gdmFyaWFibGVzDQpxcGxvdChQb2ludFBlclNLLCBkYXRhID0gTG9uZG9uLm5vZGUsIGdlb20gPSAiaGlzdG9ncmFtIikNCiNnZ3Bsb3QoTG9uZG9uLm5vZGUsIGFlcyh4PSJQb2ludFBlclNLIiwgeT1Qb2ludFBlclNLKSkrZ2VvbV9ib3hwbG90KCkjKHRoaXMgaXMgYW5vdGhlciBjb2RlIGZvciBib3hwbG90IGluIGdncGxvdDIpDQojcXBsb3QoeT1Mb25kb24ubm9kZSRQb2ludFBlclNLLCB4PSAwLjEsIGdlb20gPSAiYm94cGxvdCIpICANCg0KcXBsb3QoSW5kZXgsIGRhdGEgPSBpbmRleC5kYXRhZnJhbWUsIGdlb20gPSAiaGlzdG9ncmFtIikNCiNxcGxvdCh5PSBpbmRleC5kYXRhZnJhbWUkSW5kZXgsIHg9IDAuMSwgZ2VvbSA9ICJib3hwbG90IikgIA0KDQojdGhlIHZhcmlhYmxlcyBsb29rIG5vcm1hbGx5IGRpc3RyaWJ1dGVkLGJ1dCB3ZSBzaG91bGQgY29uc2lkZXIgdGhlIG91dGxpZXJzDQpwbG90KExvbmRvbi5ub2RlJFBvaW50UGVyU0ssaW5kZXguZGF0YWZyYW1lU0YkSW5kZXgsY29sPSJibHVlIikNCiNhZnRlciBzY2F0dGVyIHBsb3QsIHdlIHNob3VsZCByZW1vdmUgIkxhZHkgTWFyZ2FyZXQiIGFzIGl0cyB1bnVzdWFsIHJvYWQgaW50ZXJzZWN0aW9uIGRlbnNpdHkobWF5YmUgZHVlIHRvIHRoZSByZXNpZGVudGlhbCByb2FkIGludGVyc2VjdGlvbnMgYXJlIGluY2x1ZGVkKQ0KDQpub2RlLmluZGV4LmZyYW1lIDwtbWVyZ2UoaW5kZXguZGF0YWZyYW1lLExvbmRvbi5ub2RlLCBieS54PSJnc3NfY29kZV93YXJkIixieS55PSJnc3NfY29kZV93YXJkIixhbGw9VFJVRSkgDQojcmVtb3ZlIG91dGxpZXItLUxhZHkgTWFyZ2FyZXQoRTA1MDAwMTgxKQ0KI25vZGUuaW5kZXguZnJhbWUgPC0gbm9kZS5pbmRleC5mcmFtZVtub2RlLmluZGV4LmZyYW1lJFBvaW50UGVyU0s8MzAwLF0NCiNsaW5lYXIgcmVncmVzc2lvbiBwbG90DQpxcGxvdChQb2ludFBlclNLLEluZGV4LGRhdGE9bm9kZS5pbmRleC5mcmFtZSxnZW9tID0gInBvaW50IikgKyBzdGF0X3Ntb290aChtZXRob2Q9ImxtIiwgc2U9RkFMU0UsIHNpemU9MSkNCiNmaXQgdGhlIGxpbmVhciBtb2RlbA0KbW9kZWwgPC0gbG0oUG9pbnRQZXJTSyB+IEluZGV4LCBkYXRhID1ub2RlLmluZGV4LmZyYW1lKQ0KI3Jlc2lkdWFsIGRhdGFmcmFtZQ0KbGlicmFyeShicm9vbSkNCm1vZGVsX3JlcyA8LSB0aWR5KG1vZGVsKQ0Kc3VtbWFyeShtb2RlbCkNCnBsb3QobW9kZWwpDQoNCg0KYGBgDQpGaXR0aW5nIGEgUXVhZHJhdGljIE1vZGVsDQpgYGB7cn0NCiNidWlsZCBhIFF1YWRyYXRpYyBNb2RlbA0Kbm9kZS5pbmRleC5mcmFtZSRQb2ludFBlclNLMiA8LSAobm9kZS5pbmRleC5mcmFtZSRQb2ludFBlclNLKV4yDQpxdWFkcmF0aWMubW9kZWwgPC1sbShJbmRleCB+IFBvaW50UGVyU0sgKyAoUG9pbnRQZXJTSzIpLGRhdGEgPW5vZGUuaW5kZXguZnJhbWUpDQpwbG90KHF1YWRyYXRpYy5tb2RlbCApDQpzdW1tYXJ5KHF1YWRyYXRpYy5tb2RlbCkNCiNGaXR0aW5nIGEgUXVhZHJhdGljIE1vZGVsDQpQb2ludFBlclNLdmFsdWVzIDwtIHNlcSgwLDMwMCwgMC4wMSkNCnByZWRpY3RlZGNvdW50cyA8LSBwcmVkaWN0KHF1YWRyYXRpYy5tb2RlbCxsaXN0KFBvaW50UGVyU0s9UG9pbnRQZXJTS3ZhbHVlcywgUG9pbnRQZXJTSzI9UG9pbnRQZXJTS3ZhbHVlc14yKSkNCnBsb3Qobm9kZS5pbmRleC5mcmFtZSRQb2ludFBlclNLLCBub2RlLmluZGV4LmZyYW1lJEluZGV4ICwgcGNoPTE2LCB4bGFiID0gIlBvaW50UGVyU0siLCB5bGFiID0gIkluZGV4IiwgY2V4LmxhYiA9IDAuOCwgY29sID0gImJsYWNrIikNCmxpbmVzKFBvaW50UGVyU0t2YWx1ZXMsIHByZWRpY3RlZGNvdW50cywgY29sID0gImJsdWUiLCBsd2QgPTIpDQpgYGANCg0KVGhlIGNvZWZmaWNpZW50IChlc3RpbWF0ZSkgaW4gdGhlIHN1bW1hcnkoKSB0YWJsZSBzaG93cyB0aGF0KG9uIGF2ZXJhZ2UpIGZvciBhIDEgdW5pdCAoZGF5KSBpbmNyZWFzZSBpbiB1bmF1dGhvcmlzZWQgYWJzZW5jZSBmcm9tIHNjaG9vbCwgdGhlcmUgaXMgYSByZWR1Y3Rpb24gaW4gdGhlIGF2ZXJhZ2UgR0NTRSBwb2ludCBzY29yZSBvZiAtMjkuODc0Lg0KDQpUaGUgcC12YWx1ZXMgZm9yIHRoZSBpbnRlcmNlcHQgYW5kIHRoZSBjb2VmZmljaWVudCBhcmUgaGlnaGx5IHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgKDwwLjAwMSkgc28gd2UgY2FuIHJlbHkgb24gdGhlIHJlbGF0aW9uc2hpcCB0aGF0IGlzIGJlaW5nIG9ic2VydmVkLg0KDQpUaGUgYWRqdXN0ZWQgUi1zcXVhcmVkIHN0YXRpc3RpYyBpcyAwLjM4LCB3aGljaCB0ZWxscyB1cyB0aGF0IDM4JSBvZiB0aGUgdmFyaWF0aW9uIGluIEdDU0Ugc2NvcmVzIGFjcm9zcyBXYXJkcyBpbiBMb25kb24gY2FuIGJlIGV4cGxhaW5lZCBieSB2YXJpYXRpb24gaW4gdW5hdXRob3Jpc2VkIGFic2VuY2UgZnJvbSBzY2hvb2wgKHdoaWNoIGlzIHF1aXRlIGEgbG90IGZvciBhIHNpbmdsZSB2YXJpYWJsZSkuDQoNCkludGVycm9nYXRpbmcgdGhlIGxhc3QgZ3JhcGggaW4gcGxvdChtb2RlbDEpd2hpY2ggaXMgYSBzY2F0dGVyIHBsb3Qgb2YgZml0dGVkIHZhbHVlcyAodGhlIG1vZGVsIGVzdGltYXRlcyBhY2hpZXZlZCBieSBwbHVnZ2luZyB0aGUgdmFsdWVzIGFuZCBjb2VmZmljaWVudHMgYmFjayBpbnRvIHRoZSByZWdyZXNzaW9uIGVxdWF0aW9uKSBhZ2FpbnN0IHN0YW5kYXJkaXNlZCByZXNpZHVhbHMsIHdlIGNhbiBzZWUgbm8gYXBwYXJlbnQgcGF0dGVybnMgaW4gdGhlIGNsb3VkIG9mIHBvaW50cywgd2hpY2ggc3VnZ2VzdHMgdGhlIG1vZGVsIGhhcyBub3QgdmlvbGF0ZWQgYW55IGltcG9ydGFudCBhc3N1bXB0aW9ucy4NCg0KIyNUZXN0IGZvciBzcGF0aWFsIHBhdHRlcm5zDQp3ZSBzaG91ZCB0ZXN0IHRoYXQgaXMgdGhlcmUgYW55IHNwYXRpYWwgY2x1c3RlcmluZyBvZiByZXNpZHVhbHMuSWYgdGhlc2UgcGxhY2VzIGNsdXN0ZXIgaW4gc3BhY2UsIHRoZW4gdGhlcmUgbWlnaHQgYmUgc29tZSB1bm9ic2VydmVkIHVuZGVybHlpbmcgZmFjdG9yIGNhdXNpbmcgdGhpcy4gVGhpcyBpcyBpbXBvcnRhbnQgaXMgaXQgbWVhbnMgdGhhdCB0aGUgYXNzdW1wdGlvbiBvZiBpbmRlcGVuZGVuY2UgdGhhdCByZWdyZXNzaW9uIG1vZGVscyByZWx5IHVwb24gbWlnaHQgYmUgdmlvbGF0ZWQuDQpOb3cgaW4gb3VyIGNhc2UgaGVyZSwgdGhlcmUgaXMgbm90IGEgY2xlYXIgdmlvbGF0aW9uIG9mIHNwYXRpYWwgaW5kZXBlbmRlbmNlLCBidXQgaXQgaXMgY2VydGFpbmx5IGhpbnRlZCBhdC4NCiB0ZXN0IGZvciBzcGF0aWFsIHBhdHRlcm5zIChzcGF0aWFsIGF1dG9jb3JyZWxhdGlvbikgdXNpbmcgdGhlIE1vcmFuJ3MgSSBzdGF0aXN0aWMNCmBgYHtyfQ0KIyMjIFRlc3QgZm9yIHNwYXRpYWwgcGF0dGVybnMgKHNwYXRpYWwgYXV0b2NvcnJlbGF0aW9uKSB1c2luZyB0aGUgTW9yYW4ncyBJIHN0YXRpc3RpYw0KI2NvcHkgYSBuZXcgTG9uZG9uV2FyZFNGDQpMb25kb25XYXJkU0YucGF0dGVybiA8LSBMb25kb25XYXJkU0YNCkxvbmRvbldhcmRTRi5wYXR0ZXJuJG1vZGVsX3Jlc2lkcyA8LSBtb2RlbCRyZXNpZHVhbHMNCkxvbmRvbldhcmRTRi5wYXR0ZXJuIDwtIExvbmRvbldhcmRTRi5wYXR0ZXJuWyEoaXMubmEoTG9uZG9uV2FyZFNGLnBhdHRlcm4kbW9kZWxfcmVzaWRzKSApLF0NCkxvbmRvbldhcmRTUC5wYXR0ZXJuIDwtIGFzKExvbmRvbldhcmRTRi5wYXR0ZXJuLCJTcGF0aWFsIikNCnRtYXBfbW9kZSgidmlldyIpDQpxdG0oTG9uZG9uV2FyZFNGLnBhdHRlcm4sZmlsbD0nbW9kZWxfcmVzaWRzJykNCg0KDQpgYGANCg0KYGBge3J9DQojbGlicmFyeShzcGRlcCkNCiNDYWxjdWxhdGUgdGhlIGNlbnRyb2lkcyBvZiBMb25kb24gd2FyZHMNCmNlbnRXYXJkIDwtIGNvb3JkaW5hdGVzKExvbmRvbldhcmRTUC5wYXR0ZXJuKQ0KcGxvdChjZW50V2FyZCkNCiNHZW5lcmF0ZSB0aGUgc3BhdGlhbCB3ZWlnaHRzIG1hdHJpeCx1c2luZyBiaW5hcnkgbWF0cml4IG9mIHF1ZWVuJ3MgY2FzZSBuZWlnaGJvdXJzDQojY3JlYXRlIG5laWdoYm91cnMgbGlzdA0KDQpsaWJyYXJ5KHNwZGVwKQ0KbmVpZ2hib3VyIDwtIHBvbHkybmIoTG9uZG9uV2FyZFNQLnBhdHRlcm4scXVlZW49VCkNCiNwbG90DQpwbG90KG5laWdoYm91cixjb29yZGluYXRlcyhjZW50V2FyZCksY29sPSJyZWQiKQ0KcGxvdChMb25kb25XYXJkU1AucGF0dGVybixhZGQ9VCkNCiNjcmVhdGUgc3BhdGlhbCB3ZWlnaHRzIG9iamVjdCBmcm9tIHRoZXNlIHdlaWdodHMNClNwYXRpYWxXZWlnaHQgPC0gbmIybGlzdHcobmVpZ2hib3VyLHN0eWxlPSJDIix6ZXJvLnBvbGljeT1UKQ0KI1J1biBtb3JhbiBJIHRlc3QNCm1vcmFuLnRlc3QoTG9uZG9uV2FyZFNQLnBhdHRlcm5AZGF0YSRtb2RlbF9yZXNpZHMsIFNwYXRpYWxXZWlnaHQsemVyby5wb2xpY3k9VCkNCmBgYA0Kc28gaGVyZSB3ZSBoYXZlIGEgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCBidXQgcmVsYXRpdmVseSB3ZWFrIGluZGljYXRpb24gdGhhdCB0aGVyZSBpcyBzb21lIHNwYXRpYWwgY2x1c3RlcmluZyBvZiByZXNpZHVhbCB2YWx1ZXMuIEEgdmFsdWUgb2YgMC4wNyAoMSBiZWluZyBwZXJmZWN0IHNwYXRpYWwgYXV0b2NvcnJlbGF0aW9uLCAwIGJlaW5nIG5vbmUgYXQgYWxsKSBzaG93cyB0aGF0IHRoZXJlIGlzIG5vIGV2aWRlbmNlIHRoYXQgaGlnaCByZXNpZHVhbCB2YWx1ZXMgY2x1c3RlciBuZWFyIGhpZ2ggdmFsdWVzIGFuZCBsb3cgcmVzaWR1YWwgdmFsdWVzIGNsdXN0ZXIgbmVhciBsb3dlciB2YWx1ZXMuDQoNCg0KI211bHRpIGxpbmVhciByZWdyZXNzaW9uIG1vZGVsDQpgYGB7cn0NCiMjI0ZvciBhIGRlZXBlciByZXNlYXJjaCwgd2Ugd2lsbCBidWlsZCBhIG11bHRpcGxlIGxpbmVhciByZWdyZXNzaW9uIG1vZGVsIHRvIGZpbmQgd2hldGhlciB0aGUgdXJiYW4gdml0YWxpdHkgaW5kZXggaGFzIGEgcmVsYXRpb25zaGlwIHdpdGggdXJiYW4gdml0YWxpdHkgc3ViLWZhY3RvcnMuIElmIHNvLCB3aGljaCBvbmUgaXMgdGhlIHN0cm9uZ2VzdCBvciB3ZWFrZXN0Lg0KIw0KbGlicmFyeShjb3JycGxvdCkNCmNvcm1hdCA8LSBjb3Iobm9kZS5pbmRleC5mcmFtZVssYyg1OjgsMTYpXSwgdXNlPSJjb21wbGV0ZS5vYnMiLCBtZXRob2Q9InBlYXJzb24iKQ0KY29ycnBsb3QoY29ybWF0KQ0KI3JSdW4gbXVsdGlwbGUgcmVncmVzc2lvbiBtb2RlbA0KbW9kZWxfbXVsdGkgPC0gbG0oUG9pbnRQZXJTSyB+IE1peEluZGV4Lm5vcm1hbGl6YXRpb24rRGVuc2l0eS5ub3JtYWxpemF0aW9uICsgYWNjZXNzLm1lYW4gKyBFY29BY3Qubm9ybWFsaXphdGlvbiwgZGF0YSA9IG5vZGUuaW5kZXguZnJhbWUpDQpzdW1tYXJ5KG1vZGVsX211bHRpKQ0KYGBgDQoNCmBgYHtyfQ0KIyNzYW1lIGFzIHJlc2lkdWFsIGF1dG9jb3JyZWxhdGlvbiBhbmFseXNpcyBhYm92ZQ0KbW9kZWxfcmVzX211bHRpIDwtIHRpZHkobW9kZWxfbXVsdGkpDQpzdW1tYXJ5KG1vZGVsX211bHRpKQ0KcGxvdChtb2RlbF9tdWx0aSkNCkxvbmRvbldhcmRTRi5wYXR0ZXJuJG1vZGVsX3Jlc2lkc19tdWx0aSA8LSBtb2RlbF9tdWx0aSRyZXNpZHVhbHMNCkxvbmRvbldhcmRTUC5wYXR0ZXJuIDwtIGFzKExvbmRvbldhcmRTRi5wYXR0ZXJuLCJTcGF0aWFsIikNCnRtYXBfbW9kZSgidmlldyIpDQpxdG0oTG9uZG9uV2FyZFNGLnBhdHRlcm4sZmlsbD0nbW9kZWxfcmVzaWRzX211bHRpJykNCmxpYnJhcnkoc3BkZXApDQpuZWlnaGJvdXIgPC0gcG9seTJuYihMb25kb25XYXJkU1AucGF0dGVybixxdWVlbj1UKQ0KI2NyZWF0ZSBzcGF0aWFsIHdlaWdodHMgb2JqZWN0IGZyb20gdGhlc2Ugd2VpZ2h0cw0KU3BhdGlhbFdlaWdodCA8LSBuYjJsaXN0dyhuZWlnaGJvdXIsc3R5bGU9IkMiLHplcm8ucG9saWN5PVQpDQojUnVuIG1vcmFuIEkgdGVzdA0KbW9yYW4udGVzdChMb25kb25XYXJkU1AucGF0dGVybkBkYXRhJG1vZGVsX3Jlc2lkc19tdWx0aSwgU3BhdGlhbFdlaWdodCx6ZXJvLnBvbGljeT1UKQ0KYGBgDQoNCg==